package com.zjny.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import com.zjny.constant.CommonConstant;

import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * <p>
 * 流处理工具包
 * </p>
 *
 * @author cui haida
 * 2024/04/30/11:17
 */
public class StreamUtils {

    /**
     * 将collection过滤
     * StreamUtils.filter(list, Objects::nonNull)
     *
     * @param collection 需要转化的集合
     * @param function   过滤方法
     * @return 过滤后的list
     */
    public static <E> List<E> filter(Collection<E> collection, Predicate<E> function) {
        if (CollUtil.isEmpty(collection)) {
            return CollUtil.newArrayList();
        }
        // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
        return collection.stream().filter(function).collect(Collectors.toList());
    }

    /**
     * 将collection拼接
     *
     * @param collection 需要转化的集合
     * @param function   拼接方法
     * @return 拼接后的list
     */
    public static <E> String join(Collection<E> collection, Function<E, String> function) {
        return join(collection, function, CommonConstant.SPLIT_DOU);
    }

    /**
     * 将collection拼接
     *
     * @param collection 需要转化的集合
     * @param function   拼接方法
     * @param delimiter  拼接符
     * @return 拼接后的list
     */
    public static <E> String join(Collection<E> collection, Function<E, String> function, CharSequence delimiter) {
        if (CollUtil.isEmpty(collection)) {
            return StringUtils.EMPTY;
        }
        return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter));
    }

    /**
     * 将collection排序
     *
     * @param collection 需要转化的集合
     * @param comparing  排序方法
     * @return 排序后的list
     */
    public static <E> List<E> sorted(Collection<E> collection, Comparator<E> comparing) {
        if (CollUtil.isEmpty(collection)) {
            return CollUtil.newArrayList();
        }
        // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
        return collection.stream().filter(Objects::nonNull).sorted(comparing).collect(Collectors.toList());
    }

    /**
     * 合并两个相同key类型的map
     *
     * @param map1  第一个需要合并的 map
     * @param map2  第二个需要合并的 map
     * @param merge 合并的lambda，将key  value1 value2合并成最终的类型,注意value可能为空的情况
     * @param <K>   map中的key类型
     * @param <X>   第一个 map的value类型
     * @param <Y>   第二个 map的value类型
     * @param <V>   最终map的value类型
     * @return 合并后的map
     */
    public static <K, X, Y, V> Map<K, V> merge(Map<K, X> map1, Map<K, Y> map2, BiFunction<X, Y, V> merge) {
        // 检查两个map是否都为空，如果都为空，则返回一个空的map
        if (MapUtil.isEmpty(map1) && MapUtil.isEmpty(map2)) {
            return MapUtil.newHashMap();
            // 检查map1是否为空，如果为空，则初始化map1为一个空的map
        } else if (MapUtil.isEmpty(map1)) {
            map1 = MapUtil.newHashMap();
            // 检查map2是否为空，如果为空，则初始化map2为一个空的map
        } else if (MapUtil.isEmpty(map2)) {
            map2 = MapUtil.newHashMap();
        }

        // 获取两个map的所有key，放入一个set中，以确保覆盖所有key
        Set<K> key = new HashSet<>();
        key.addAll(map1.keySet());
        key.addAll(map2.keySet());

        // 创建一个新的map用于存放合并后的结果
        Map<K, V> map = new HashMap<>();
        for (K t : key) {
            // 获取对应key的value，可能为null
            X x = map1.get(t);
            Y y = map2.get(t);
            // 应用合并函数，生成新的value
            V z = merge.apply(x, y);
            // 如果合并结果不为null，则放入新的map中
            if (z != null) {
                map.put(t, z);
            }
        }
        return map;
    }
}
